export default {
  data() {
    return {
      currentOption: [],
      currentOptionValue: [], // 分解得到option的value数组，不包含disabled的项 作用：键盘操作选中时使用，无搜索时为全部的option，搜索时为搜索到的value数组
      currentAllOptionValue: [], // 分解得到option的value数组，包含disabled的项
      currentValue: [], // 被选中的option的value数组，单选时只有一项，多选时有多项
      currentSelectedItems: [],
      currentAllowCreateOption: [], // 新建的条目，初始化时需要合并到currentOption中
      allowCreateOption: null, // allowCreate将要新建的条目，还没确认创建，确认创建之后会添加到currentOption数组
      visible: false,
      hoverItemValue: '', // 被hover的option的value值
      keySelectValue: '', // 预选的value,键盘操作时回车选中
      isFilter: false, // 是否搜索 不是远程搜索
      filterableValue: [], // 搜索到的value数组
      renderType: this.option ? 'option' : 'slot', // 渲染类型，option为数据渲染，slot为插槽渲染
      scrollInnerHeight: 0,
      isFocused: false,
    }
  },
  methods: {
    initValue() {
      if (this.multiple && Array.isArray(this.value)) {
        this.currentValue = JSON.parse(JSON.stringify(this.value)) || []
      } else if (
        typeof this.value === 'string' ||
        typeof this.value === 'number'
      ) {
        this.currentValue = this.value.toString() ? [this.value] : []
      }
      this.setCurrentSelectedItems()
    },
    initOption() {
      if (this.renderType === 'option') {
        this.currentOption = (this.option || []).concat(
          this.currentAllowCreateOption
        )
      } else if (this.renderType === 'slot') {
        this.currentOption = this.formatSlotOption().concat(
          this.currentAllowCreateOption
        )
      }
      this.reduceOptionValue()
      this.initValue()
      this.$nextTick(this.setScrollInnerHeight())
    },
    // allowCreate将要新建的条目
    handleAllowCreate(value) {
      this.keySelectValue = value
      if (!value || this.currentAllOptionValue.includes(value)) {
        this.allowCreateOption = null
        return
      }
      this.allowCreateOption = {
        value: value,
        label: value,
      }
    },
    // allowCreate确认新建
    handleConfirmAllowCreate() {
      const deepData = JSON.parse(JSON.stringify(this.allowCreateOption))
      this.allowCreateOption = null
      this.isFilter = false
      this.currentOption.push(deepData)
      this.currentOptionValue.push(deepData.value)
      this.currentAllOptionValue.push(deepData.value)
      this.handleOptionClick(deepData.value)
      // 数据改变需要在最后一步，因为需要在最后触发initOption 不能在之前触发
      this.currentAllowCreateOption.push(deepData)
    },
    reduceOptionValue() {
      if (this.isFilter) return
      const deepData = JSON.parse(JSON.stringify(this.currentOption))

      const currentOptionValue = []
      const currentAllOptionValue = []

      deepData.forEach((item) => {
        if (item.option && Array.isArray(item.option)) {
          item.option.forEach((oItem) => {
            currentAllOptionValue.push(oItem.value)
            !oItem.disabled && currentOptionValue.push(oItem.value)
          })
        } else {
          currentAllOptionValue.push(item.value)
          !item.disabled && currentOptionValue.push(item.value)
        }
      })

      this.currentOptionValue = currentOptionValue
      this.currentAllOptionValue = currentAllOptionValue
    },
    // 格式化slotoption数据
    formatSlotOption(vNodes) {
      const slotOption = vNodes || this.$slots.default
      const currentOption = []
      if (slotOption) {
        // eslint-disable-next-line no-unused-vars
        for (const option of slotOption) {
          const Instance = option.componentInstance
          const Options = option.componentOptions
          const tag =
            (Instance && Instance.componentName) || (Options && Options.tag)
          if (tag === 'OptionGroup') {
            const optionGorup = {}
            const label = Options.propsData.label
            optionGorup.label = label
            optionGorup.option = []
            optionGorup.option = this.formatSlotOption(Options.children)
            currentOption.push(optionGorup)
          } else if (tag === 'Option') {
            let label = Options.propsData.label
            if (!label) {
              Options.children.forEach((item) => {
                if (item.text && !label) label = item.text.trim()
              })
            }
            currentOption.push({
              value: Options.propsData.value,
              label: label || Options.propsData.value,
              disabled: Options.propsData.disabled || false,
            })
          }
        }
      }
      return currentOption
    },
    // option 点击
    handleOptionClick(value) {
      if (!value.toString()) return
      let deepValue = JSON.parse(JSON.stringify(this.currentValue))

      // 多选时是否要删除改项
      let isRemove = false

      if (this.multiple) {
        if (deepValue.includes(value)) {
          const index = deepValue.findIndex((item) => {
            return item === value
          })
          deepValue.splice(index, 1)
          isRemove = true
        } else {
          deepValue.push(value)
        }
      } else {
        deepValue = [value]
      }

      this.keySelectValue = value
      this.isFilter = false
      this.allowCreateOption = null

      if (
        this.multiple &&
        this.multipleLimit > 0 &&
        deepValue.length > this.multipleLimit
      ) {
        // 多选限制
        return
      }
      if (JSON.stringify(deepValue) !== JSON.stringify(this.currentValue)) {
        this.currentValue = deepValue
        this.setCurrentSelectedItems(value, isRemove)
        this.updateDropdownPosition()

        this.emitInputAndChange()
      } else {
        if (this.multiple && this.filterable && !this.remote) {
          this.isFilter = false
          this.reduceOptionValue()
        } else {
          this.setDropDownVisible(false)
        }
      }
    },
    handleOptionNavigate(num = 0) {
      if (!this.currentOptionValue.length) return
      let nextValue = this.currentOptionValue[0]
      if (this.keySelectValue) {
        let index = this.currentOptionValue.findIndex(
          (item) => item === this.keySelectValue
        )
        index = index + num
        if (index > this.currentOptionValue.length - 1) index = 0
        if (index < 0) index = this.currentOptionValue.length - 1

        nextValue = this.currentOptionValue[index]
      }
      this.keySelectValue = nextValue
    },
    // 设置当前选中项数据
    setCurrentSelectedItems(value, isRemove) {
      if (isRemove) {
        const index = this.currentSelectedItems.findIndex(
          (item) => item.value === value
        )
        if (index > -1) {
          this.currentSelectedItems.splice(index, 1)
        }
      } else {
        const deepData = JSON.parse(JSON.stringify(this.currentSelectedItems))
        this.currentOption.forEach((item) => {
          if (item.option && Array.isArray(item.option)) {
            item.option.forEach((oItem) => {
              const index = this.currentValue.indexOf(oItem.value)
              if (index > -1) {
                deepData[index] = {
                  value: oItem.value,
                  label: oItem.label,
                }
              }
            })
          } else {
            const index = this.currentValue.indexOf(item.value)
            if (index > -1) {
              deepData[index] = {
                value: item.value,
                label: item.label,
              }
            }
          }
        })
        this.currentSelectedItems = deepData
      }
    },
    // option hover变化
    handleOptionHover(value, hover) {
      this.hoverItemValue = hover ? value : ''
    },
    // 设置visible
    setDropDownVisible(visible = null) {
      if (visible === null) {
        this.visible = !this.visible
      } else {
        this.visible = visible
      }
      if (this.visible) {
        this.isFilter =
          this.allowCreate && this.filterable ? this.isFilter : false
        this.reduceOptionValue()
        this.$nextTick(this.setScrollInnerHeight())
      }
    },
    // 搜索filterable
    handleFilterable(value) {
      const filterableValue = []
      const currentOptionValue = []
      if (value) {
        this.isFilter = true
        this.currentOption.forEach((item) => {
          if (item.option && Array.isArray(item.option)) {
            item.option.forEach((oItem) => {
              if (oItem.label.includes(value)) filterableValue.push(oItem.value)
              if (oItem.label.includes(value) && !oItem.disabled)
                currentOptionValue.push(oItem.value)
            })
          } else {
            if (item.label.includes(value)) filterableValue.push(item.value)
            if (item.label.includes(value) && !item.disabled)
              currentOptionValue.push(item.value)
          }
        })
        this.currentOptionValue = currentOptionValue
      } else {
        this.isFilter = false
        this.reduceOptionValue()
      }
      this.filterableValue = filterableValue
    },
    // 更新dropdown的位置
    updateDropdownPosition() {
      this.visible && this.$refs.dropDown && this.$refs.dropDown.updatePopper()
    },
    // clearable清空
    handleClearable() {
      this.currentValue = []
      this.keySelectValue = ''
      this.currentSelectedItems = []
      this.hoverItemValue = ''
      this.filterableValue = []
      this.isFilter = false
      this.reduceOptionValue()
      this.updateDropdownPosition()
      this.$emit('clear')
      this.emitInputAndChange()
      if (this.remote && this.filterable) this.emitRemoteChange()
    },
    emitRemoteChange(value) {
      this.$emit('remote-change', value || '')
    },
    emitInputAndChange() {
      if (this.multiple) {
        if (this.filterable) {
          this.isFilter = false
          this.reduceOptionValue()
        }

        this.$emit('input', this.currentValue)
        this.$emit(
          'change',
          this.valueLable ? this.currentSelectedItems : this.currentValue
        )
      } else {
        this.$emit('input', this.currentValue[0])
        this.$emit(
          'change',
          this.valueLable ? this.currentSelectedItems[0] : this.currentValue[0]
        )

        this.setDropDownVisible(false)
      }
    },
    // 多选tag关闭触发
    handleTagClose(value) {
      const index = this.currentValue.findIndex((item) => item === value)
      if (index > -1) {
        this.currentValue.splice(index, 1)
        this.currentSelectedItems.splice(index, 1)
        this.emitInputAndChange()
      }
    },
    // 设置dropInner的高度
    setScrollInnerHeight() {
      setTimeout(() => {
        const scrollInner = this.$refs.scrollInner
        const scrollOuter = this.$refs.scrollOuter
        const maxHeight = parseFloat(this.maxHeight)

        let targetPaddingTop = 5
        let targetPaddingBottom = 5
        if (scrollOuter) {
          if (window.getComputedStyle) {
            targetPaddingTop = window.getComputedStyle(scrollOuter, null)[
              'paddingTop'
            ]
            targetPaddingBottom = window.getComputedStyle(scrollOuter, null)[
              'paddingBottom'
            ]
          } else if (scrollOuter.currentStyle) {
            targetPaddingTop = scrollOuter.currentStyle['paddingTop']
            targetPaddingBottom = scrollOuter.currentStyle['paddingBottom']
          }
        }
        if (scrollInner) {
          let scrollInnerHeight = scrollInner.offsetHeight
          if (scrollInnerHeight > maxHeight) {
            scrollInnerHeight = maxHeight
          }
          this.scrollInnerHeight =
            scrollInnerHeight +
            parseFloat(targetPaddingTop) +
            parseFloat(targetPaddingBottom) +
            2
        }
      })
    },
    // outside点击
    handleOutsideClick(event) {
      if (this.visible) {
        if (this.renderHtml !== false) {
          const { $el } = this.$refs.dropDown
          if ($el === event.target || $el.contains(event.target)) {
            return
          }
        }
      }

      this.setDropDownVisible(false)
    },
    // 设置scroll的位置
    setScrollToPosition() {
      const dropDown = this.$refs.dropDown
      const focusOption =
        dropDown &&
        dropDown.$el.getElementsByClassName(`${this.optionPrefix}__focus`)[0]
      if (focusOption) {
        let top = focusOption.offsetTop
        const height = focusOption.offsetHeight

        const parentOptionGroup = focusOption.parentNode.parentNode
        const parentOptionGroupWrap = focusOption.parentNode
        const parentOptionGroupClass = `${this.optionPrefix}-group`
        if (
          parentOptionGroup.getAttribute('class') === parentOptionGroupClass
        ) {
          top =
            top + parentOptionGroupWrap.offsetTop + parentOptionGroup.offsetTop
        }

        const bottomTop = parseInt(top + height)
        const maxHeight = parseInt(this.maxHeight)

        if (bottomTop > maxHeight) {
          const y = bottomTop - maxHeight
          const position = {
            x: 0,
            y: y,
          }
          this.$refs.scroll && this.$refs.scroll.scrollTo(position, 200)
        }

        if (bottomTop <= maxHeight) {
          const position = {
            x: 0,
            y: 0,
          }
          this.$refs.scroll && this.$refs.scroll.scrollTo(position, 200)
        }
      }
    },
    handleKeydown(event) {
      const key = event.key || event.code
      if (key === 'Backspace') {
        return // so we don't call preventDefault
      }
      if (this.visible) {
        event.preventDefault()
        if (key === 'Tab') {
          event.stopPropagation()
        }
        if (key === 'Escape') this.setDropDownVisible(false)
        if (key === 'Enter') {
          if (
            this.allowCreate &&
            this.allowCreateOption &&
            this.allowCreateOption.value === this.keySelectValue
          ) {
            this.handleConfirmAllowCreate()
          } else {
            this.handleOptionClick(this.keySelectValue)
          }
        }
        if (key === 'ArrowUp') {
          this.handleOptionNavigate(-1)
          setTimeout(() => {
            this.setScrollToPosition()
          })
        }
        if (key === 'ArrowDown') {
          this.handleOptionNavigate(1)
          setTimeout(() => {
            this.setScrollToPosition()
          })
        }
      } else {
        if (['ArrowUp', 'ArrowDown'].includes(key))
          this.setDropDownVisible(true)
      }
    },
  },
  watch: {
    option: {
      handler() {
        this.initOption()
      },
      deep: true,
      immediate: true,
    },
    value() {
      this.initValue()
    },
  },
}
